/*	$Id: status.c 1056 2010-04-21 03:51:21Z phrakt $	*/
/*
 * Copyright (c) 2003 Jean-Francois Brousseau <phrakt@gmail.com>
 * All rights reserved.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 *
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. The name of the author may not be used to endorse or promote products
 *    derived from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES,
 * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
 * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
 * THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
 * EXEMPLARY, OR CONSEQUENTIAL  DAMAGES (INCLUDING, BUT NOT LIMITED TO,
 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
 * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
 * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
 * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */

#include <sys/types.h>
#include <sys/stat.h>
#include <sys/fcntl.h>
#include <sys/socket.h>

#include <netinet/in.h>
#include <arpa/inet.h>

#include <errno.h>
#include <stdlib.h>
#include <string.h>
#include <netdb.h>
#include <unistd.h>

#include <canopy/log.h>

#include "http.h"
#include "stat.h"
#include "private.h"


/*
 * HTTP status codes
 * =================
 *
 * This table contains all the information on HTTP status codes.
 */

#define HTTP_STATUS_CLASS(s)     (s / 100)
#define HTTP_STATUS_CODE(s)      (s % 100)


static struct http_code http_codes[5][20] = {
	{
		{ HTTP_STAT_CONTINUE,     "Continue",                   NULL },
		{ HTTP_STAT_SWITCHPROTO,  "Switching Protocols",        NULL },
	},
	{
		{ HTTP_STAT_OK,           "OK",                         NULL },
		{ HTTP_STAT_CREATED,      "Created",                    NULL },
		{ HTTP_STAT_ACCEPTED,     "Accepted",                   NULL },
		{ HTTP_STAT_NOCONTENT,    "No Content",                 NULL },
		{ HTTP_STAT_RESETCONT,    "Reset Content",              NULL },
		{ HTTP_STAT_PARTIALCONT,  "Partial Content",            NULL },
	},
	{
		{ HTTP_STAT_MULTCHOICES,  "Multiple Choices",           NULL },
		{ HTTP_STAT_MOVEDPERM,    "Moved Permanently",          NULL },
		{ HTTP_STAT_FOUND,        "Found",                      NULL },
		{ HTTP_STAT_SEEOTHER,     "See Other",                  NULL },
		{ HTTP_STAT_NOTMODIFIED,  "Not Modified",               NULL },
		{ HTTP_STAT_USEPROXY,     "Use Proxy",                  NULL },
		{ HTTP_STAT_UNUSED,       "(unused)",                   NULL },
		{ HTTP_STAT_TEMPREDIRECT, "Temporary Redirect",         NULL },
	},
	{
		{ HTTP_STAT_BADREQUEST,  "Bad Request",                 NULL },
		{ HTTP_STAT_UNAUTH,      "Unauthorized",                NULL },
		{ HTTP_STAT_PAYMENTREQ,  "Payment Required",            NULL },
		{ HTTP_STAT_FORBIDDEN,   "Forbidden",                   NULL },
		{ HTTP_STAT_NOTFOUND,    "Not Found",                   NULL },
		{ HTTP_STAT_NOTALLOWED,  "Method Not Allowed",          NULL },
		{ HTTP_STAT_NOTACCEPT,   "Not Acceptable",              NULL },
		{ HTTP_STAT_PROXYAUTH, "Proxy Authentication Required", NULL },
		{ HTTP_STAT_REQTIMEOUT,  "Request Timeout",             NULL },
		{ HTTP_STAT_CONFLICT,    "Conflict",                    NULL },
		{ HTTP_STAT_GONE,        "Gone",                        NULL },
		{ HTTP_STAT_LENGTHREQ,   "Length Required",             NULL },
		{ HTTP_STAT_PRECOND,     "Precondition Failed",         NULL },
		{ HTTP_STAT_ENTTOOLARGE, "Request Entity Too Large",    NULL },
		{ HTTP_STAT_URITOOLONG,  "Request-URI Too Long",        NULL },
		{ HTTP_STAT_UNSUPMEDIA,  "Unsupported Media Type",      NULL },
		{ HTTP_STAT_REQRANGE, "Requested Range Not Satisfiable", NULL },
		{ HTTP_STAT_EXPECT,      "Expectation Failed",          NULL },
	},
	{
		{ HTTP_STAT_INTERNALERR,  "Internal Server Error",      NULL },
		{ HTTP_STAT_NOTIMPL,      "Not Implemented",            NULL },
		{ HTTP_STAT_BADGATEWAY,   "Bad Gateway",                NULL },
		{ HTTP_STAT_UNAVAILABLE,  "Service Unavailable",        NULL },
		{ HTTP_STAT_GTWTIMEOUT,   "Gateway Timeout",            NULL },
		{ HTTP_STAT_HTTPVERSION,  "HTTP Version Not Supported", NULL },
	}
};

/* number of valid entries in each status class */
static int http_class_nbcodes[] = { 0, 2, 7, 8, 18, 6 };


/*
* http_status_getdesc()
*
*/

const char*
http_status_getdesc(int status)
{
	int class, code;

	class = HTTP_STATUS_CLASS(status);
	code = HTTP_STATUS_CODE(status);
	if ((class > 5) || (code >= http_class_nbcodes[class])) {
		http_log_warn("invalid status code %d", status);
		return (NULL);
	}

	return (http_codes[class - 1][code].hc_desc);
}
